﻿using Elsa;
using Elsa.Activities.Http.Services;
using Elsa.Events;
using Elsa.Persistence.EntityFramework.Core.Extensions;
using Elsa.Persistence.EntityFramework.SqlServer;
using Elsa.Providers.WorkflowContexts;
using MediatR;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using SqlSugar;
using System.Reflection;
using Zhp.Common.Appsetting;
using Zhp.Common.Helper;
using Zhp.Common.Extention;
using Zhp.Workflow.Activities;
using Zhp.Workflow.Activities.DataOptions;
using Zhp.Workflow.Entity;
using Zhp.Workflow.Middleware;
using Zhp.Workflow.Models;
using Zhp.Workflow.Notify;
using Zhp.Workflow.Notify.Services;
using Zhp.Workflow.Services;
using Elsa.Persistence.EntityFramework.MySql;

namespace Zhp.Workflow.Extensions
{
    public static class WorkflowSetup
    {
        private static string _connectionStringName = "ConnectionString";
        public static void AddWorkflowSetup(this IServiceCollection services)
        {
            services.AddSingleton<AuthenticationBasedHttpEndpointAuthorizationHandler>();
            var elsaSection = AppHelper.Configuration.GetSection("Elsa");
            var dbType = AppHelper.Configuration.GetConnectionString("DbType").ToEnum<DbType>();
            var connectionString = AppHelper.Configuration.GetConnectionString(_connectionStringName);
            // Elsa services.
            services.AddElsa(elsa => elsa
                    .UseEntityFrameworkPersistence(ef =>
                    {
                        if (dbType == DbType.SqlServer)
                        {
                            ef.UseSqlServer(connectionString);
                        }
                        else if (dbType == DbType.MySql)
                        {
                            ef.UseMySql(connectionString);
                        }
                    })
                    .AddConsoleActivities()
                    .AddJavaScriptActivities()
                    //.AddHttpActivities(elsaSection.GetSection("Server").Bind)
                    .AddHttpActivities(x =>
                    {
                        x.BaseUrl = new Uri(elsaSection.GetSection("Server:BaseUrl").Value);
                        x.HttpEndpointAuthorizationHandlerFactory = sp => sp.GetRequiredService<AuthenticationBasedHttpEndpointAuthorizationHandler>();
                    })
                    .AddQuartzTemporalActivities()
                    .AddActivity<ApproveActivity>()
            );

            // Elsa API endpoints.
            services.AddElsaApiEndpoints();
            // For Dashboard.
            services.AddRazorPages();

            //注册实体，流程上下文使用
            var program = AppSettingHelper.GetOptions<ProgramCodeOptions>();
            services.AddEntity(program.EntityName);
            services.AddBookmarkProvider<ApproveBookmarkProvider>();
            services.AddTransient(typeof(ITodoService), typeof(TodoService));
            services.AddTransient(typeof(IWorkflowService), typeof(WorkflowService));
            services.AddTransient(typeof(IApproverDataProvider), typeof(ApproverDataProvider));
            services.AddTransient(typeof(INotificationHandler<WorkflowExecutionFinished>), typeof(WorkflowExecutionFinishedHander));
            services.AddTransient(typeof(INotificationHandler<WorkflowCompleted>), typeof(WorkflowCompletedHander));
            services.AddTransient(typeof(INotificationHandler<WorkflowSuspended>), typeof(WorkflowSuspendedHander));

            ConsoleHelper.WriteLine($"Elsa工作流服务注入成功", ConsoleColor.Green);
        }

        public static void UseWorkflow(this IApplicationBuilder app)
        {
            app.UseHttpActivities();
            app.UseMiddleware<WorkflowMiddleware>();

            //初始化工作流中自定义的表
            var options = AppSettingHelper.GetOptions<SysDataOptions>();
            if (options.InitDatabase)
            {
                var db = app.ApplicationServices.GetService<ISqlSugarClient>();
                if (db != null)
                {
                    db.CodeFirst.InitTables<WorkflowApproverRecord>();
                    db.CodeFirst.InitTables<WorkflowNotify>();
                    db.CodeFirst.InitTables<WorkflowTodo>();
                }
            }
        }

        private static void AddEntity(this IServiceCollection services, string assembly)
        {
            var serviceAssembly = Assembly.LoadFrom(Path.Combine(AppContext.BaseDirectory, $"{assembly}.dll"));
            var types = serviceAssembly.GetTypes();
            foreach (var item in types)
            {
                if (typeof(IBaseWorkflow).IsAssignableFrom(item))
                {
                    Type implementationType = typeof(WorkflowRefresher<>).MakeGenericType(item);
                    services.AddTransient(typeof(IWorkflowContextProvider), implementationType);
                }
            }
        }
    }
}
